from flask import g, request
from wtforms import Form, StringField
import wtforms as wf
import wtforms.validators as vd
from app.libs.exception import AuthFailed, ParameterException
from app.libs.forms.validators import IDValidator, NullableEmailValidator, PathValidator, TypeValidator, UrlUnquote, VSSpeedValidator, VSStepValidator
from app.libs.utils import Pager


class BaseForm(Form):
    ''' 
    统一处理Form错误信息
    when check_token is True， set g.current_user = user that is payload user
    '''
    LANGUAGES = ['zh']  # 并没有生效
    token = None

    def __init__(self, get_token=True):
        """  when check_token is True， set g.current_user = user that is payload user """
        # data type : json form-data， 可以不需要传参数
        # args = request.args  # immutable dict # @RISK 还不支持URL传参的获取

        if get_token:
            self.token = self.__get_token()
        data = request.get_json(silent=True)  # dict or None
        form_data = request.form  # immutable dict
        super().__init__(data=data, formdata=form_data, file=request.files.get('file'))

    @classmethod
    def __get_token(cls):
        token = request.headers.get(
            'token', default=None, type=str) or request.form.get('token', default=None)
        if not token:
            raise AuthFailed('请传入token再请求')
        g.token = token
        return token  # 获取当前请求的用户信息

    def check_validate(self) -> Form:
        """ 质疑返回异常处理，而不需要手动处理 """
        valid = super(Form, self).validate()
        if not valid:
            raise ParameterException(msg=self.errors)
        return self

# token的校验是否集成到这


class TestForm(BaseForm):

    account = wf.StringField(
        validators=[vd.data_required(), vd.length(min=3, max=5)])
    path = wf.StringField(validators=[PathValidator()])


class IDForm(BaseForm):  # 传入ID的校验器
    id = wf.IntegerField(validators=[IDValidator()])


# 检验器
class RegisterForm(BaseForm):

    nickname = wf.StringField(validators=[vd.length(max=20)])
    account = wf.StringField(
        validators=[vd.data_required(), vd.length(min=4, max=20)])
    password = wf.StringField(
        validators=[vd.data_required(), vd.length(min=4, max=20)])
    email = wf.EmailField(validators=[NullableEmailValidator()])


class LoginForm(BaseForm):
    account = StringField(
        validators=[vd.DataRequired(), vd.Length(min=4, max=20)])
    password = wf.StringField(
        validators=[vd.DataRequired(), vd.Length(min=4, max=20)])


class requestForm(BaseForm):
    """ 用于校验请求的课程 | 视频 | 章节 信息 """
    type = wf.IntegerField(validators=[TypeValidator()])
    id = wf.IntegerField(validators=[IDValidator()])


class SearchForm(BaseForm):

    key = wf.SearchField(validators=[vd.DataRequired(), vd.Length(max=30)])
    type = wf.IntegerField(validators=[TypeValidator()])
    id = wf.IntegerField(
        validators=[IDValidator()])


class TypeForm(BaseForm):
    type = wf.IntegerField(validators=[TypeValidator()])


class VSConfigForm(BaseForm):
    step = wf.Field(validators=[VSStepValidator()], default=None)
    speed = wf.Field(validators=[VSSpeedValidator()], default=None)
    min_process_box_height = wf.IntegerField()
    min_searcher_box_with_height = wf.IntegerField()


class UploadFileForm(BaseForm):
    file = wf.FileField(validators=[vd.data_required()])
    type = wf.IntegerField(validators=[TypeValidator()])
    chapter_id = wf.IntegerField(validators=[IDValidator(nullable=True)])
    course_id = wf.IntegerField(validators=[IDValidator(nullable=True)])
    vsConfigForm: VSConfigForm


class UploadByPathForm(BaseForm):
    path = wf.StringField(validators=[PathValidator()])
    type = wf.IntegerField(validators=[TypeValidator()])
    vsConfigForm: VSConfigForm


class ResourceByIDForm(BaseForm):
    # @RISK id的校验写的不好，如果增加了新的类型，无法判断，也需要大篇幅的修改
    type = wf.IntegerField(validators=[TypeValidator()])
    id = wf.IntegerField(validators=[IDValidator()])


class GetOneByUrlForm(BaseForm):
    url = wf.URLField(validators=[vd.url(), UrlUnquote()])
    type = wf.IntegerField(validators=[TypeValidator()])


class GetResourceListForm(BaseForm):
    type = wf.IntegerField(validators=[TypeValidator()])
    offset = wf.IntegerField(validators=[vd.number_range(min=0)], default=0)
    limit = wf.IntegerField(validators=[vd.number_range(min=0)], default=0)

    @property
    def pager(self) -> Pager:
        if hasattr(self, '_pager'):  # 单例模式
            return self._pager
        offset = self.data.get('offset')
        limit = self.data.get('limit')
        setattr(self, '_pager', Pager(offset, limit))
        return self._pager
